#include <stdio.h>
#include <stdlib.h>

// 
#include "errormanager.h"
#include "messages.h"
// #include "outputAPI.h"
#include "swmm_output.h"

// 动态库操作库函数
#ifdef _WIN32
	#include <Windows.h>
#else
	#include <dlfcn.h>
#endif
//#define F_OFF _off64_t
#ifdef WINDOWS
    /*#define F_OFF off64_t      */
	#ifdef __MINGW32__
		#define F_OFF _off64_t
	#else
    	#define F_OFF __int64
	#endif
#else
    #define F_OFF off_t
#endif
// define fseeko64 in different platform
#ifdef WINDOWS
    #ifdef __MINGW32__
       int (*fseeko64_)(FILE*, F_OFF, int) = &fseeko64;
    #else
        int (*fseeko64_)(FILE*, F_OFF, int) = &_fseeki64;
    #endif
#else
     int (*fseeko64_)(FILE*, F_OFF, int) = &fseeko;
#endif

int main(int argc, char* argv[]){
	
// 目的：读取out文件中指定点的时间序列结果
// argv1：输出文件路径
// argv2：节点索引
// argv3：节点属性，可从下列值中选取
//        SMO_invert_depth,        
//        SMO_hydraulic_head,      
//        SMO_stored_ponded_volume,
//        SMO_lateral_inflow,      
//        SMO_total_inflow,        
//        SMO_flooding_losses,     
//        SMO_pollutant_conc_node  
// argv4: 输出文件路径
// Example: read_ts trace_J24.out 2 SMO_pollutant_conc_node trace_J24_COD.txt

	// 输出文件路径
	char path[MAXFILENAME];
	strcpy(path, argv[1]);
	printf("test output file path: %s\n",path);

	// 节点索引
	int nodeIndex;
	sscanf(argv[2], "%d", &nodeIndex);
	// char nodeIndex_c[5];
	// strcpy(nodeIndex_c, argv[2]);
	// nodeIndex = (int) (nodeIndex_c);

	// 节点属性
	SMO_nodeAttribute nodeAttr;
	char nodeAttr_c[25];
	strcpy(nodeAttr_c, argv[3]);

	// 输出文件名
	char outFile[259];
	strcpy(outFile, argv[4]);

	// 处理动态库文件 --------------------------------------------------------------
	// 导入库文件
	#ifdef _WIN32
		HMODULE module = LoadLibrary("libswmmoutputapi.dll");
	#else
		void* module = dlopen("libswmmoutputapi.so", RTLD_LAZY);
	#endif
	if (module == NULL){
		printf("Failed to load dll\n");
	}
	#ifdef _WIN32
	// 定义SMO_open函数，并指向dll中的对应函数，打开文件
	typedef int(*dll_SMO_open)(SMO_Handle*, const char*);
	dll_SMO_open SMO_open =
		(dll_SMO_open)GetProcAddress(module, "SMO_open");
	// 定义SMO_getProjectSize函数，并指向dll中的对应函数，获取工程大小
	typedef int(*dll_SMO_getProjectSize)(SMO_Handle* smoapi,
		    int **code, int* count);
	dll_SMO_getProjectSize SMO_getProjectSize =
		(dll_SMO_getProjectSize)GetProcAddress(module, "SMO_getProjectSize");
	// 获取要素名称，并和index对应
	typedef int(*dll_SMO_getElementName)(SMO_Handle* smoapi, SMO_elementType type,
		int elementIndex, char **elementName, int *size);
	dll_SMO_getElementName SMO_getElementName =
		(dll_SMO_getElementName)GetProcAddress(module, "SMO_getElementName");
	// 定义SMO_getNodeSeries函数，读取时间序列结果
	typedef int(*dll_SMO_getNodeSeries)(SMO_Handle* smoapi, int nodeIndex, SMO_nodeAttribute attr,
					    int startPeriod, int endPeriod, float **outValueArray, int *length);
	dll_SMO_getNodeSeries SMO_getNodeSeries =
		(dll_SMO_getNodeSeries)GetProcAddress(module, "SMO_getNodeSeries");
	// SMO_getUnits，获取单位
	typedef int(*dll_SMO_getUnits)(SMO_Handle* smoapi, int **unitFlag, int *length);
	dll_SMO_getUnits SMO_getUnits =
		(dll_SMO_getUnits)GetProcAddress(module, "SMO_getUnits");
	// SMO_getFlowUnit
	typedef int(*dll_SMO_getFlowUnits)(SMO_Handle p_handle, int *unitFlag);
	dll_SMO_getFlowUnits SMO_getFlowUnits =
		(dll_SMO_getFlowUnits)GetProcAddress(module, "SMO_getFlowUnits");
	// SMO_getPollutUnit
	typedef int(*dll_SMO_getPollutantUnits)(SMO_Handle p_handle, int **unitFlag, int *length);
	dll_SMO_getPollutantUnits SMO_getPollutantUnits =
		(dll_SMO_getPollutantUnits)GetProcAddress(module, "SMO_getPollutantUnits");
	// SMO_getTime
	typedef int(*dll_SMO_getTimes)(SMO_Handle p_handle, SMO_time code, int *time);
	dll_SMO_getTimes SMO_getTimes =
		(dll_SMO_getTimes)GetProcAddress(module, "SMO_getTimes");
	// SMO_getStartDate
	typedef int(*dll_SMO_getStartDate)(SMO_Handle p_handle, double *date);
	dll_SMO_getStartDate SMO_getStartDate =
		(dll_SMO_getStartDate)GetProcAddress(module, "SMO_getStartDate");
	#else
		int(*SMO_open)(SMO_Handle*, const char*) =
			dlsym(module, "SMO_open");
		int(*SMO_getProjectSize)(SMO_Handle* smoapi, int **code, int* count) =
			dlsym(module, "SMO_getProjectSize");
		int(*SMO_getElementName)(SMO_Handle* smoapi, SMO_elementType type,
								int elementIndex, char **elementName, int *size) =
			dlsym(module, "SMO_getElementName");
		int(*SMO_getNodeSeries)(SMO_Handle* smoapi, int nodeIndex, SMO_nodeAttribute attr,
					    		int startPeriod, int endPeriod, float **outValueArray, int *length) =
			dlsym(module, "SMO_getNodeSeries");
		int(*SMO_getUnits)(SMO_Handle* smoapi, int **unitFlag, int *length) =
			dlsym(module, "SMO_getUnits");
	#endif

	//
	// 开始读取 -------------------------------------------------------------------------------
	// 初始化文件指针
	// SMO_Handle* smoapi = (SMO_Handle*)malloc(sizeof(SMO_Handle)); 
	SMO_Handle smoapi; 
	SMO_init(&smoapi);
	// 打开输出文件
	int errBEM = SMO_open(smoapi, path);
	if (errBEM != 0)
	{
		printf("Err code: %i\n", errBEM);
		return -1;
	}

	// 提取流量单位
	int unitFlag;
	SMO_getFlowUnits(smoapi, &unitFlag);
	printf("Unit Flag is: %d\n", unitFlag);

	// 提取污染物单位
	int *pollutUnitFlag;
	int Npollutes;
	SMO_getPollutantUnits(smoapi, &pollutUnitFlag, &Npollutes);
	printf("Pollutant Units: %d\n", *pollutUnitFlag);

	// 提取时间参数
	// 提取起始时间
	double startDate;
	SMO_getStartDate(smoapi, &startDate);
	printf("Start Date: %f\n", startDate);
	// 提取Nperied
	int Nperieds;
	SMO_getTimes(smoapi, 1, &Nperieds);
	printf("Nperieds: %d\n", Nperieds);
	// 提取报告步长，ReportStep
	int rptStep;
	SMO_getTimes(smoapi, 0, &rptStep);
	printf("Report Step: %d\n", rptStep);

	// 判断要提取的属性
	if (strcmp(nodeAttr_c, "SMO_invert_depth") == 0)
	{
		nodeAttr = SMO_invert_depth;
	}
	else if (strcmp(nodeAttr_c, "SMO_hydraulic_head") == 0)
	{
		nodeAttr = SMO_hydraulic_head;
	}
	else if (strcmp(nodeAttr_c, "SMO_stored_ponded_volume") == 0)
	{
		nodeAttr = SMO_stored_ponded_volume;
	}
	else if (strcmp(nodeAttr_c, "SMO_lateral_inflow") == 0)
	{
		nodeAttr = SMO_lateral_inflow;
	}
	else if (strcmp(nodeAttr_c, "SMO_total_inflow") == 0)
	{
		nodeAttr = SMO_total_inflow;
	}
	else if (strcmp(nodeAttr_c, "SMO_flooding_losses") == 0)
	{
		nodeAttr = SMO_flooding_losses;
	}
	else if (strcmp(nodeAttr_c, "SMO_pollutant_conc_node") == 0)
	{
		nodeAttr = SMO_pollutant_conc_node;
	}
	else
	{
		printf("Unkown attribute\n");
		return -1;
	}
	
	// 提取时间序列数据，默认全部提取
	float* outValueArray;	
	int node_tsLength;
	int startPeriod = 0;
	// int endPeriod = Nperieds;

	SMO_getNodeSeries(smoapi, nodeIndex, nodeAttr, startPeriod, Nperieds,
    	&outValueArray, &node_tsLength);
	printf("Time Series Data Type: %s\n", nodeAttr_c);
	printf("Time Series Data Length: %d\n", node_tsLength);


	// 数据写入文件
	FILE* fp;
	if ((fp = fopen(outFile, "w+")) == NULL)
	{
		printf("Can not open file!\n");
		exit(EXIT_FAILURE);
	}
	fprintf(fp, "timeIndex,Value\n");
	for (int n = startPeriod ; n < node_tsLength; n++)
	{
		fprintf(fp, "%5d,   %10.3f\n", n+1, outValueArray[n]);
	}
	fclose(fp);
	

	// 关闭文件
	SMO_close(&smoapi);
	// SMO_getNodeSeries
	FreeLibrary(module);

	return 0;
}
